#include "StdAfx.h"
#include "base64.h"


static const char argtbl[] =  
		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static const unsigned char b64tbl[] =  
{  
	0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36,  
	0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff,  
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01,  
	0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,  
	0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,  
	0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,  
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b,  
	0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,  
	0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,  
	0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33  
};

char* Base64Encrypt(const unsigned char* input, int cbin, unsigned char* output, int cbout)
{
	int nblock = cbin/3;
	int nleft = cbin%3;

	int idx_in = 0, idx_out = 0, i = 0, index = 0;

	unsigned int tmp;

	for(i = 0; i < nblock; i++)
	{
		tmp = (input[i*3] << 16) | (input[i*3+1] << 8) | (input[i*3+2]);

		int index = (tmp & (0x3f << 18)) >> 18;
		output[i*4] = argtbl[index];

		index = (tmp & (0x3f << 12)) >> 12;
		output[i*4+1] = argtbl[index];

		index = (tmp & (0x3f << 6)) >> 6;
		output[i*4+2] = argtbl[index];

		index = tmp & 0x3f;
		output[i*4+3] = argtbl[index];
	}

	idx_in = i*3;
	idx_out = i*4;

	if(nleft == 1)
	{
		tmp = input[idx_in];
		index = (tmp & (0x3f << 2)) >> 2;
		output[idx_out++] = argtbl[index];

		index = (tmp & 0x3) << 4;
		output[idx_out++] = argtbl[index];

		output[idx_out++] = '=';
		output[idx_out++] = '=';

	}
	else if(nleft == 2)
	{
		tmp = (input[idx_in] << 8) | input[idx_in+1];

		index = (tmp & (0x3f << 10)) >> 10;
		output[idx_out++] = argtbl[index];

		index = (tmp & (0x3f << 4)) >> 4;
		output[idx_out++] = argtbl[index];

		index = (tmp & 0xf) << 2;
		output[idx_out++] = argtbl[index];

		output[idx_out++] = '=';
	}

	output[idx_out] = '\0';

	return (char*)output;
}

int Base64Decrypt(const unsigned char* input, int cbin, unsigned char* output, int cbout)
{
	int i, v;  
	unsigned char *dst = output;  

	v = 0;  
	for (i = 0; input[i] && input[i] != '='; i++) 
	{  
		unsigned int index= input[i]-43;  
		if (index>=(sizeof(b64tbl)/sizeof(b64tbl[0])) || b64tbl[index] == 0xff)  
			return -1; 

		v = (v << 6) + b64tbl[index];  
		if (i & 3) 
		{  
			if (dst - output < cbout) {  
				*dst++ = v >> (6 - 2 * (i & 3));  
			}  
		}  
	}

	output[dst-output] = '\0';

	return (int)(dst - output);
} 

base64str::base64str(const char* str)
{
	b64str = str;
}
base64str::~base64str()
{
}

const char* base64str::encrypt()
{
	int inlen = b64str.length();
	int outlen = (inlen/3 + 1)*4 + 1;
	char* pstr = new char[outlen];

	Base64Encrypt((unsigned char*)b64str.c_str(), inlen, (unsigned char*)pstr, outlen);

	b64str = pstr;
	delete[] pstr;

	return b64str.c_str();
}
const char* base64str::decrypt()
{
	int inlen = b64str.length();
	int outlen = (inlen/4 + 1)*3 + 1;
	char* pstr = new char[outlen];

	Base64Decrypt((unsigned char*)b64str.c_str(), inlen, (unsigned char*)pstr, outlen);

	b64str = pstr;
	delete[] pstr;

	return b64str.c_str();
}

